import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.TimerTask;

public class Main {
    public static JFrame myframe;
    public static JPanel mainscreen;
    public static int[][] allwzq = new int[19][19];
    public static String xinxi = "白方下棋";
    public static boolean is_black = true;
    public static boolean is_finished = false;
    public static int max_time = 0;
    public static int black_time = 0;
    public static int white_time = 0;
    public static String black_msg = "无限制";
    public static String white_msg = "无限制";

    public static void main(String[] args) {
        myframe = new MyFrame();
    }
}
class MyFrame extends JFrame {
    public MyFrame() {
        setTitle("五子棋");
        setLayout(null);
        setSize(700, 550);
        setLocation(500, 0);
        Main.mainscreen = new MainScreen();
        Main.mainscreen.setBounds(0, 0, 700, 550);
        add(Main.mainscreen);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}
class MainScreen extends JPanel implements ActionListener, MouseListener  {
    JButton btn_start, btn_giveUp, btn_exit, btn_setting, btn_about;
    public int msg_num = 9;
    public JLabel title_label;
    public JLabel[] msg_labels = new JLabel[msg_num];
    public JPanel map_panel;
    public String[] msg_texts = new String[msg_num];
    public MainScreen() {
        initial_allwzq();
        setLayout(null);
        // 绘制棋盘范围：(5, 5, 500, 500)
        map_panel = new MapPanel();
        map_panel.setBounds(5, 5, 500, 500);
        map_panel.setOpaque(true);
        map_panel.setBackground(Color.lightGray);
        this.add(map_panel);

        title_label = new JLabel("五子棋");
        title_label.setBounds(530, 80, 130, 30);
        title_label.setBackground(Color.LIGHT_GRAY);
        title_label.setOpaque(true);
        this.add(title_label);

        btn_start = new JButton("开始");
        btn_start.setBounds(530, 130, 130, 50);
        btn_start.setMargin(new Insets(0, 0, 0, 0));
        btn_start.addActionListener(this);
        this.add(btn_start);
        btn_giveUp = new JButton("认输");
        btn_giveUp.setBounds(530, 180, 130, 50);
        btn_giveUp.setMargin(new Insets(0, 0, 0, 0));
        btn_giveUp.addActionListener(this);
        this.add(btn_giveUp);
        btn_exit = new JButton("退出");
        btn_exit.setBounds(530, 230, 130, 50);
        btn_exit.setMargin(new Insets(0, 0, 0, 0));
        btn_exit.addActionListener(this);
        this.add(btn_exit);
        btn_setting = new JButton("设置");
        btn_setting.setBounds(530, 280, 130, 50);
        btn_setting.setMargin(new Insets(0, 0, 0, 0));
        btn_setting.addActionListener(this);
        this.add(btn_setting);
        btn_about = new JButton("关于");
        btn_about.setBounds(530, 330, 130, 50);
        btn_about.setMargin(new Insets(0, 0, 0, 0));
        btn_about.addActionListener(this);
        this.add(btn_about);

        this.addMouseListener(this);
        java.util.Timer timer = new java.util.Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(Main.black_time > 0 && Main.is_black && !Main.is_finished) {
                    Main.black_time -= 1;
                    Main.black_msg = Main.black_time / 3600 + ":" + (Main.black_time/60 - Main.black_time/3600*60) + ":" + (Main.black_time-Main.black_time/60*60);
                    Main.mainscreen.repaint();
                    if(Main.black_time == 0) {
                        Main.is_finished = true;
                        JOptionPane.showMessageDialog(Main.mainscreen, "游戏结束，红方胜利！");
                    }
                }
                if(Main.white_time > 0 && !Main.is_black && !Main.is_finished) {
                    Main.white_time -= 1;
                    Main.white_msg = Main.white_time / 3600 + ":" + (Main.white_time/60 - Main.white_time/3600*60) + ":" + (Main.white_time-Main.white_time/60*60);
                    Main.mainscreen.repaint();
                    if(Main.white_time == 0) {
                        Main.is_finished = true;
                        JOptionPane.showMessageDialog(Main.mainscreen, "游戏结束，白方胜利！");
                    }
                }
            }
        }, 1000, 1000);
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == btn_start) {
            int result = JOptionPane.showConfirmDialog(this, "是否重新开始游戏？");
            if(result == 0) {
                // 重新开始游戏
                // (1)把棋盘清空
                // (2)把游戏参数复位到初始值
                intial_parameters();
            }
        }
        if(e.getSource() == btn_giveUp) {
            int result = JOptionPane.showConfirmDialog(this, "是否确认认输？");
            if(result == 0) {
                if(Main.is_black) {
                    JOptionPane.showMessageDialog(this, "白方已经认输，游戏结束！");
                } else {
                    JOptionPane.showMessageDialog(this, "红方已经认输，游戏结束！");
                }
                // 棋局结束，单击【 开始 】可重新开始游戏
                Main.is_finished = true;
            }
        }
        if(e.getSource() == btn_exit) {
            int result = JOptionPane.showConfirmDialog(this, "要退出游戏吗？");
            if(result == 0) {
                System.exit(0);
            }
        }
        if(e.getSource() == btn_setting) {
            String input = JOptionPane.showInputDialog(this, "请输入游戏的最大时间（单位：分钟）：");
            try {
                Main.max_time = Integer.parseInt(input) * 60;
                // 提示输入每方每次落子的最大时限，0表示无限制
                intial_parameters_with_dialog();
            } catch (NumberFormatException e2) {
                JOptionPane.showMessageDialog(this, "请正确输入时间！");
            }
        }
        if(e.getSource() == btn_about) {
            JOptionPane.showMessageDialog(this, "制作者：下唐人\n制作时间：2023年9月");
        }
    }
    public void initial_allwzq() {
        for(int i = 0; i < 19; i++) {
            for(int j = 0; j < 19; j++) {
                Main.allwzq[i][j] = 0;
            }
        }
    }
    public void intial_parameters_with_dialog() {
        if(Main.max_time < 0) {
            JOptionPane.showMessageDialog(this, "时间不允许负数！");
        }
        if(Main.max_time == 0) {
            int r = JOptionPane.showConfirmDialog(this, "设置完成，重新开始游戏！");
            if(r == 0) {
                initial_allwzq();
                Main.xinxi = "白方先行";
                Main.is_black = true;
                Main.black_time = Main.max_time;
                Main.white_time = Main.max_time;
                Main.black_msg = "无限制";
                Main.white_msg = "无限制";
                Main.is_finished = false;
                this.repaint();
            }
        }
        if(Main.max_time > 0) {
            int r = JOptionPane.showConfirmDialog(this, "设置完成，重新开始游戏！");
            if(r == 0) {
                initial_allwzq();
                Main.xinxi = "白方先行";
                Main.is_black = true;
                Main.black_time = Main.max_time;
                Main.white_time = Main.max_time;
                Main.black_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
                Main.white_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
                Main.is_finished = false;
                this.repaint();
            }
        }
    }
    public void intial_parameters() {
        if(Main.max_time < 0) {
            JOptionPane.showMessageDialog(this, "时间不允许负数！");
        }
        if(Main.max_time == 0) {
            initial_allwzq();
            Main.xinxi = "白方先行";
            Main.is_black = true;
            Main.black_time = Main.max_time;
            Main.white_time = Main.max_time;
            Main.black_msg = "无限制";
            Main.white_msg = "无限制";
            Main.is_finished = false;
            this.repaint();
        }
        if(Main.max_time > 0) {
            initial_allwzq();
            Main.xinxi = "白方先行";
            Main.is_black = true;
            Main.black_time = Main.max_time;
            Main.white_time = Main.max_time;
            Main.black_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
            Main.white_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
            Main.is_finished = false;
            this.repaint();
        }
    }
    @Override
    public void mouseClicked(MouseEvent mouseEvent) {
    }
    @Override
    public void mousePressed(MouseEvent e) {
        // 如果对局已经结束，则不响应
        if(Main.is_finished) {
            return;
        }
        // 获取鼠标点击位置在棋盘上的映射
        int x = (e.getX() - 65 + 10) / 20;
        int y = (e.getY() - 85 + 10) / 20;
        System.out.println(e.getX() + "," + e.getY() + "=(" + x + "," + y + ")");
        // 棋盘四方最边上的线不能落子
        if(x >= 1 && x <= 17 && y >= 1 && y <= 17) {
            if(Main.is_black) {
                if (Main.allwzq[x][y] != 0 ) { return; }
                // 白方落子
                Main.allwzq[x][y] = 1;
                // 统计白方是否胜利
                boolean flag1 = is_win(1, x, y);
                if(flag1) {
                    Main.is_finished = true;
                    JOptionPane.showMessageDialog(this, "游戏结束，白方胜利！");
                }
            } else {
                if (Main.allwzq[x][y] != 0 ) { return; }
                // 红方落子
                Main.allwzq[x][y] = 2;
                // 统计红方是否胜利
                boolean flag2 = is_win(2, x, y);
                if(flag2) {
                    Main.is_finished = true;
                    JOptionPane.showMessageDialog(this, "游戏结束，红方胜利！");
                }
            }
            if(Main.is_black) {
                Main.is_black = false;
                Main.xinxi = "红方落子";
                Main.black_time = Main.max_time;
                Main.black_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
            } else {
                Main.is_black = true;
                Main.xinxi = "白方落子";
                Main.white_time = Main.max_time;
                Main.white_msg = Main.max_time / 3600 + ":" + (Main.max_time/60 - Main.max_time/3600*60) + ":" + (Main.max_time-Main.max_time/60*60);
            }
            this.repaint();
        }
    }
    public boolean is_win(int color, int x, int y) {
        // 判断横向
        int count = 0;
        for(int i = 1; i <= 17; i++) {
            if(Main.allwzq[i][y] == color) {
                count++;
                if(count == 5) {
                    return true;
                }
            }
            if(Main.allwzq[i][y] != color) {
                count = 0;
            }
        }
        // 判断纵向
        count = 0;
        for(int i = 1; i <= 17; i++) {
            if(Main.allwzq[x][i] == color) {
                count++;
                if(count == 5) {
                    return true;
                }
            }
            if(Main.allwzq[x][i] != color) {
                count = 0;
            }
        }
        // 判断左上到右下
        count = 0;
        int start_x = x, start_y = y;
        if(x >= y) {
            start_x = x - y + 1;
            start_y = 1;
            while(start_x <= 17) {
                if(Main.allwzq[start_x][start_y] == color) {
                    count++;
                    if(count == 5) {
                        return true;
                    }
                }
                if(Main.allwzq[start_x][start_y] != color) {
                    count = 0;
                }
                start_x++;
                start_y++;
            }
        }
        if(x < y) {
            start_x = 1;
            start_y = y - x + 1;
            while(start_y <= 17) {
                if(Main.allwzq[start_x][start_y] == color) {
                    count++;
                    if(count == 5) {
                        return true;
                    }
                }
                if(Main.allwzq[start_x][start_y] != color) {
                    count = 0;
                }
                start_x++;
                start_y++;
            }
        }
        // 判断右上到左下
        count = 0;
        start_x = x;
        start_y = y;
        if(x <= 17 - y + 1) {
            start_x = x + y - 1;
            start_y = 1;
            while(start_x >= 1) {
                if(Main.allwzq[start_x][start_y] == color) {
                    count++;
                    if(count == 5) {
                        return true;
                    }
                }
                if(Main.allwzq[start_x][start_y] != color) {
                    count = 0;
                }
                start_x--;
                start_y++;
            }
        }
        if(x > 17 - y + 1) {
            start_x = 17;
            start_y = y - 17 + x;
            while(start_y <= 17) {
                if(Main.allwzq[start_x][start_y] == color) {
                    count++;
                    if(count == 5) {
                        return true;
                    }
                }
                if(Main.allwzq[start_x][start_y] != color) {
                    count = 0;
                }
                start_x--;
                start_y++;
            }
        }
        return false;
    }
    @Override
    public void mouseReleased(MouseEvent mouseEvent) {
    }
    @Override
    public void mouseEntered(MouseEvent mouseEvent) {
    }
    @Override
    public void mouseExited(MouseEvent mouseEvent) {
    }
}
class MapPanel extends JPanel {
    public void paint(Graphics g) {
        // 双缓冲技术防止屏幕闪烁
        BufferedImage bi = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
        Graphics g1 = bi.createGraphics();
        // 绘制标题、双方信息
        g1.drawString("游戏信息：" + Main.xinxi, 130, 45);
        g1.drawString("白方时间：" + Main.black_msg, 80, 480);
        g1.drawString("红方时间：" + Main.white_msg, 310, 480);
        // 绘制棋盘
        for(int i = 0; i < 19; i++) {
            g1.drawLine(60, 80+20*i, 420, 80+20*i);
            g1.drawLine(60+20*i, 80, 60+20*i, 440);
        }
        // 标注点位
        g1.fillOval(98, 138, 4, 4);
        g1.fillOval(98, 258, 4, 4);
        g1.fillOval(98, 378, 4, 4);

        g1.fillOval(218, 138, 4, 4);
        g1.fillOval(218, 258, 4, 4);
        g1.fillOval(218, 378, 4, 4);

        g1.fillOval(338, 138, 4, 4);
        g1.fillOval(338, 258, 4, 4);
        g1.fillOval(338, 378, 4, 4);

        // 绘制全部棋子
        draw_allwzq(g1);
        // 将缓冲区的图片显示出来
        g.drawImage(bi, 0, 0, this);
    }
    public void draw_allwzq(Graphics g1) {
        for(int i = 0; i < 19; i++) {
            for(int j = 0; j < 19; j++) {
                if(Main.allwzq[i][j] == 1) {
                    int tempX = i*20+60;
                    int tempY = j*20+80;
                    g1.setColor(Color.WHITE);
                    g1.fillOval(tempX-7, tempY-7, 14, 14);
                }
                if(Main.allwzq[i][j] == 2) {
                    int tempX = i*20+60;
                    int tempY = j*20+80;
                    g1.setColor(Color.RED);
                    g1.fillOval(tempX-7, tempY-7, 14, 14);
                    g1.setColor(Color.WHITE);
                    g1.drawOval(tempX-7, tempY-7, 14, 14);
                }
            }
        }
    }
}